package io.gitee.minelx.example.geohash;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Bits {
    private final List<Boolean> entries;

    private Bits(List<Boolean> entries) {
        this.entries = entries;
    }

    public Bits reverse() {
        List<Boolean> result = new ArrayList<>(entries);
        Collections.reverse(result);
        return Bits.of(result);
    }

    public int decimal() {
        return IntStream.range(0, entries.size())
                .filter(entries::get)
                .map(index -> (int) Math.pow(2, index))
                .sum();
    }

    public Bits at(int left, int right) {
        return Bits.of(entries.subList(left, right));
    }

    public Bits stack(Bits another) {
        if (entryCounts() < another.entryCounts()) {
            throw new IllegalArgumentException("host entry counts < another entry counts.");
        }

        List<Boolean> result = new ArrayList<>();
        for (int index = 0; index < another.entryCounts(); index++) {
            result.add(at(index));
            result.add(another.at(index));
        }
        if (entryCounts() > another.entryCounts()) {
            result.add(entries.get(entries.size() - 1));
        }
        return of(result);
    }

    public Boolean at(int index) {
        return entries.get(index);
    }

    public int entryCounts() {
        return entries.size();
    }

    @Override
    public String toString() {
        return "Bits{" +
                "entries=" + entries +
                '}';
    }

    public static Bits of(List<Boolean> entries) {
        return new Bits(entries);
    }

    Stream<Bits> partition(int size) {
        return IntStream.range(0, entryCounts() / size)
                .map(self -> self * size)
                .mapToObj(index -> at(index, index + size));
    }
}
